﻿using System;
using System.Collections;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Web;
using System.Web.Configuration;
using Elmah;

namespace OrbitOne.Elmah.HttpModule
{
    public class O1ErrorLogModule : ErrorLogModule
    {
        private const string REDIRECTION_QUERY_STRING_NAME = "IssueId";
        private const string INTERNAL_SERVER_ERROR_STATUS_CODE = "500";
        private const string CUSTOM_ERRORS_CONFIG_SECTION = "system.web/customErrors";


        protected override ErrorLog ErrorLog
        {
            get
            {
                return O1XmlFileErrorLog.Default;
            }
        }

        protected override void LogException(Exception e, HttpContext context)
        {
            if (e == null)
            {
                Trace.Write("e was null");
                return;
            }

            // Fire an event to check if listeners want to filter out logging of the uncaught exception.

            ExceptionFilterEventArgs args = new ExceptionFilterEventArgs(e, context);
            OnFiltering(args);

            if (args.Dismissed)
                return;

            // Log away...
            Guid errorId = Guid.Empty;
            try
            {
                Error err = new Error(e, context);
                string strErrorId = ErrorLog.Log(err);
                errorId = new Guid(strErrorId);

            }
            catch (Exception localException)
            {
                // IMPORTANT! We swallow any exception raised during the logging and send them out to the trace . The idea 
                // here is that logging of exceptions by itself should not be  critical to the overall operation of the application.
                // The bad thing is that we catch ANY kind of exception, even system ones and potentially let them slip by.
                Trace.Write(localException.Message);
            }
            finally
            {
                RedirectToErrorPage(errorId);
            }
        }

        private void RedirectToErrorPage(Guid issueId)
        {
            try
            {
                string redirectUrl;
#if NET_1_1 
			Assembly assembly = Assembly.GetAssembly(typeof(System.Web.HttpApplication));
			BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.GetField |
				BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
			Type type = assembly.GetType("System.Web.CustomErrors");

			Object config = (Object)ConfigurationSettings.GetConfig("system.web/customErrors");
			IDictionary obj = (IDictionary)type.InvokeMember("_codeRedirects", flags, null, config, new object[] { });
			if(obj["500"]==null)
			{
				return;
			}
			redirectUrl = redirectUrl = obj["500"] as string;
#else
                CustomErrorsSection customErrorSection =
                    (CustomErrorsSection)ConfigurationSettings.GetConfig(CUSTOM_ERRORS_CONFIG_SECTION);

                redirectUrl = customErrorSection.DefaultRedirect;

                if (customErrorSection.Errors[INTERNAL_SERVER_ERROR_STATUS_CODE] == null &&
                    string.IsNullOrEmpty(redirectUrl))
                {
                    return;
                }
                if (customErrorSection.Errors[INTERNAL_SERVER_ERROR_STATUS_CODE] != null)
                {
                    redirectUrl = customErrorSection.Errors[INTERNAL_SERVER_ERROR_STATUS_CODE].Redirect;
                }
#endif

                if (redirectUrl.Length > 0)
                {

                    if (redirectUrl.IndexOf("?") == -1)
                    {
                        HttpContext.Current.Response.Redirect(string.Format("{0}?{1}={2}",
                                                                            redirectUrl,
                                                                            REDIRECTION_QUERY_STRING_NAME,
                                                                            issueId.ToString("P")));
                    }
                    else
                    {
                        HttpContext.Current.Response.Redirect(string.Format("{0}&{1}={2}",
                                                                            redirectUrl,
                                                                            REDIRECTION_QUERY_STRING_NAME,
                                                                            issueId.ToString("P")));
                    }
                }
            }
            catch (Exception localException)
            {
                Trace.Write(localException.Message);
            }
        }
    }
}
